package ace.cmp.json.jackson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Caspar
 */
public class JacksonUtils {

  public static <T> Object parseObject(String json, Class<T> cl) {
    try {
      return getObjectMapper().readValue(json, cl);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static <T> T parseObject(String json, Type type) {
    TypeReference<T> typeReference =
        new TypeReference<T>() {
          @Override
          public Type getType() {
            return type;
          }
        };
    try {
      return getObjectMapper().readValue(json, typeReference);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static String toJson(Object value) {
    try {
      return getObjectMapper().writeValueAsString(value);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static <V, K> Map<K, V> parseToMap(String json, Class<K> clk, Class<V> clv) {
    MapType typeReference =
        getObjectMapper().getTypeFactory().constructMapType(HashMap.class, clk, clv);
    try {
      return getObjectMapper().readValue(json, typeReference);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static <T> List<T> parseArray(String json, Class<T> cls) {
    CollectionType collectionType =
        getObjectMapper().getTypeFactory().constructCollectionType(List.class, cls);
    try {
      return getObjectMapper().readValue(json, collectionType);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  private static ObjectMapper getObjectMapper() {
    return ObjectMapperFactory.getDefaultObjectMapper();
  }
}
